require 'mongrel_patches/http_response_with_native_sendfile'

# This filter makes Mongrel send the file date contained 
# at the location in the X-Sendfile header as the body of the response;
# at the cost of hacking Mongrel's "write only" response HeaderOut.
#
# Usage:
#   mongrel_rails start -S lib/x_sendfile_filter.rb
#
class XSendfileFilter < HttpHandler
  FilePathHeader = 'X-Sendfile'.freeze
  StatusHeader = 'X-Mongrel-Sendfile-Status'.freeze
  FileSizeHeader = 'Content-Length'.freeze

  def process(request, response)
    if response.header.send(:instance_variable_get, :@sent)[FilePathHeader]
      # Since the response headers have already been written 
      # and they are write-only, we must manually split & reconstruct 
      # them to pop the file path X-Sendfile header.
      new_response = HttpResponse.new(response.socket)
      new_response.status = response.status
      file_path, file_size = nil, nil
      response.header.out.rewind
      response.header.out.read.split("\r\n").each do |e| 
        r = /([^:]+):\s*(.+)/.match(e)
        case 
        when r[1] == FilePathHeader
          file_path = r[2]
        when r[1] == FileSizeHeader
          file_size = r[2].to_i
        else
          new_response.header[r[1]] = r[2]
        end
      end
      new_response.send_status( file_size || File.size( file_path ))
      new_response.header[StatusHeader] = "streaming"
      new_response.send_header
      new_response.send_file(file_path, file_size < Const::CHUNK_SIZE * 2)
    end
  rescue Errno::ENOENT
    new_response.header[StatusHeader] = "The file specified by #{FilePathHeader} does not exist."
    new_response.send_status( 0 )
    new_response.send_header
  end
end

uri "/", :handler => XSendfileFilter.new  # Mongrel::Configurator::uri
